package svr

import (
	"gitee.com/yysf-xin/dproxy/pkg/db"
	"gitee.com/yysf-xin/dproxy/pkg/tools"
	"golang.org/x/net/proxy"
	"net"
	"sync"
)

type TunnelServer struct {
	Name   string
	Tunnel *db.Tunnel
	Dialer proxy.Dialer
	l      net.Listener
	mux    sync.Mutex
}

func (t *TunnelServer) String() string {
	return t.Name
}

func (t *TunnelServer) Start() (err error) {
	tools.Log.Println("start", t.Tunnel.Name, t.Tunnel.Local, "=>", t.Tunnel.Target)
	t.l, err = net.Listen("tcp", t.Tunnel.Local)
	if err == nil {
		go t.Serve()
	}
	return
}

func (t *TunnelServer) Stop() {
	if t.l != nil {
		t.mux.Lock()
		defer t.mux.Unlock()
		if t.l == nil {
			return
		}
		err := t.l.Close()
		if err != nil {
			tools.Log.Println(t.Tunnel.Name, "closed err", err)
		}
		t.l = nil
	}
}

func (t *TunnelServer) Serve() {
	for {
		conn, err := t.l.Accept()
		if err != nil && err != net.ErrClosed {
			tools.Log.Println(t.Tunnel.Name, "stopped err", err)
			break
		}
		tools.Log.Println("open", t.Tunnel.Name, t.Tunnel.Target)
		go func() {
			defer conn.Close()
			target, err := t.Dialer.Dial("tcp", t.Tunnel.Target)
			if err != nil {
				tools.Log.Println(t.Tunnel.Name, "dial fail", err)
			} else {
				tools.CopyAndWait(conn, target)
			}
			tools.Log.Println("closed", t.Tunnel.Name, t.Tunnel.Target)
		}()
	}
	tools.Log.Println(t.Tunnel.Name, "stopped")
}
